#ifndef MEASUREWORKPIECE_H
#define MEASUREWORKPIECE_H

#include <iostream>
#include <algorithm>
#include <thread>
#include <cmath>

using namespace std;

#include <QObject>
#include <QMap>
#include <QPoint>
#include <QDebug>

#include "opencv2/opencv.hpp"
using namespace cv;

#include "workpiecebuff.h"

const int MAX_THREAD_NUM_MEASURE        = 1  ;
const int MAX_WORKPIECE_BUFFER_NUM      = 100;
const int MAX_WAIT_WORKPIECE_NUM        = 100;  // 如果等待100个工件后，
                                                // 还有其他的工件的图片不完整，停止等待该工件信息
const int MAX_IMAGE_NUM_E452            = 3  ;
const int MAX_IMAGE_NUM_E575            = 3  ;
const int MAX_IMAGE_NUM_E616            = 5  ;
const int MAX_IMAGE_NUM_E618            = 5  ;

// 图像号
enum PictureId {
    PICTURE_ID_1  = 1   ,
    PICTURE_ID_2  = 2   ,
    PICTURE_ID_3  = 3   ,
    PICTURE_ID_4  = 4   ,
    PICTURE_ID_5  = 5   ,
    PICTURE_ID_7  = 7   ,
    PICTURE_ID_8  = 8   ,
    PICTURE_ID_13 = 13  ,
    PICTURE_ID_36 = 36  ,         // 基准图
    PICTURE_ID_37 = 37  ,
};

enum WorkpieceType
{
    WORKPIECE_TYPE_E452 = 1,
    WORKPIECE_TYPE_E575 = 2,
    WORKPIECE_TYPE_E616 = 3,
    WORKPIECE_TYPE_E618 = 4,
};

// 图像信息
struct ImageInfo {
    cv::Mat         image       ;
    int             workpieceId ;
    int             pictureId   ;
};

// 工件信息
class WorkpieceInfo {
public:
    WorkpieceInfo() : imageNum(0)    ,
                      workpieceId(0) ,
                      curPictureId(0),
                      channelId(0)   ,
                      fixtureId(0)
    {

    }

    bool IsWorkpieceUseable(int type) {
        bool isWorkpieceUseable = false;
        switch (type) {
        case WORKPIECE_TYPE_E452:
            isWorkpieceUseable = (imageNum == MAX_IMAGE_NUM_E452);
            break;
        case WORKPIECE_TYPE_E575:
            isWorkpieceUseable = (imageNum == MAX_IMAGE_NUM_E575);
            break;
        case WORKPIECE_TYPE_E616:
            isWorkpieceUseable = (imageNum == MAX_IMAGE_NUM_E616);
            break;
        case WORKPIECE_TYPE_E618:
            isWorkpieceUseable = (imageNum == MAX_IMAGE_NUM_E618);
            break;
        default:
            break;
        }
        return isWorkpieceUseable;
    }

    bool IsPictureUseable(int type, int pictureId) {
        bool isUseable = false;
        switch (type) {
        case WORKPIECE_TYPE_E452:
            isUseable = IsPictureUseableE452(pictureId);
            break;
        case WORKPIECE_TYPE_E575:
            isUseable = IsPictureUseableE575(pictureId);
            break;
        case WORKPIECE_TYPE_E616:
            isUseable = IsPictureUseableE616(pictureId);
            break;
        case WORKPIECE_TYPE_E618:
            isUseable = IsPictureUseableE618(pictureId);
            break;
        default:
            break;
        }
        return isUseable;
    }

    bool IsPictureUseableE452(int pictureId)
    {
        bool isPictureUseable = false;
        switch (pictureId) {
        case PICTURE_ID_13:
        case PICTURE_ID_37:
        case PICTURE_ID_36:
            isPictureUseable = (imageNum == MAX_IMAGE_NUM_E452);
        default:
            break;
        }
        return isPictureUseable;
    }

    bool IsPictureUseableE575(int pictureId)
    {
        // TODO
        bool isPictureUseable = false;
        switch (pictureId) {
        case PICTURE_ID_1:
        case PICTURE_ID_2:
        case PICTURE_ID_5:
            isPictureUseable = (imageNum == MAX_IMAGE_NUM_E575);
        default:
            break;
        }
        return isPictureUseable;
    }

    bool IsPictureUseableE616(int pictureId)
    {
        // TODO
        bool isPictureUseable = false;
        switch (pictureId) {
        case PICTURE_ID_3:
        case PICTURE_ID_4:
        case PICTURE_ID_7:
        case PICTURE_ID_1:
        case PICTURE_ID_8:
            isPictureUseable = (imageNum == MAX_IMAGE_NUM_E616);
        default:
            break;
        }
        return isPictureUseable;
    }

    bool IsPictureUseableE618(int pictureId)
    {
        // TODO
        bool isPictureUseable = false;
        switch (pictureId) {
        case PICTURE_ID_3:
        case PICTURE_ID_4:
        case PICTURE_ID_7:
        case PICTURE_ID_1:
        case PICTURE_ID_8:
            isPictureUseable = (imageNum == MAX_IMAGE_NUM_E618);
        default:
            break;
        }
        return isPictureUseable;
    }

public:
    int                  workpieceId            ;
    int                  channelId              ;
    int                  fixtureId              ;   // 治具Id
    int                  curPictureId           ;   // 工件信息到来时，当前的图像序号
    uchar                imageNum               ;   // 该工件已获得的图像数
    QMap<uchar, cv::Mat> imageMap               ;   // <图号，图像数据>
    QMap<uchar, QPoint>  imageDatumOffsetMap    ;   // <图号，图像相对于基准图像的偏移>
};

struct MeasureItemStandardVal {
    float standardVal;
    float upperTolerance;
    float lowerTolerance;
};

class MeasureWorkpiece : public QObject
{
    Q_OBJECT
public:
    explicit MeasureWorkpiece(QObject *parent = nullptr);
    ~MeasureWorkpiece();

    virtual bool SetTemplatePath(const std::string &path) = 0;
    virtual bool SetStandardVal(const std::map<std::string, MeasureItemStandardVal> &standardValMap) = 0;
    virtual void SetWorkpieceInfo(const std::string &modeName,
                          const std::string &workpieceType = "");
    virtual void CacheData(const cv::Mat &image     ,
                           const QPoint &datumOffset,
                           int workpieceId          ,
                           int pictureId            ,
                           int channelId            ,
                           int fixtureId) = 0;

    virtual void ProcessData() = 0;
    virtual bool GetDatumPixelDistance(const QImage &img,
                               int fixtureId,
                               QMap<QString, float> &pixelDistance) = 0;

    /***********************************************************************
     *  @function InitThread
     *  @brief    初始化量测线程
     *  @param
     *  @return
    ***********************************************************************/
    virtual void InitThread() = 0;

    /***********************************************************************
     *  @function
     *  @brief
     *  @param
     *  @return
    ***********************************************************************/
    virtual void ExitThread() = 0;

    /***********************************************************************
     *  @function QImageToCvMat
     *  @brief    QImage转cv::mat
     *  @param
     *  @return
    ***********************************************************************/

signals:
    void MesurementResultResponse(int workpieceId,
                                  int PictureId,
                                  int channelId,
                                  int fixtureId,
                                  const std::map<std::string, float> &measureInfo, //
                                  const QMap<QString, QString> &error);

};
//Q_DECLARE_METATYPE(Workpiece::MeasureInfo)

#endif // MEASUREWORKPIECE_H
